#include "list.h"

#ifdef LIS_DBG
#define dbg(...)		printf("%s: ", __func__), printf(__VA_ARGS__)
#else
#define dbg(...)		
#endif

void print_list(symboll_t **ptr) {
	for(; *ptr != NULL; ptr = &((*ptr)->next)) {
		if((*ptr)->type == LABEL_DEF)
			dbg("LABEL_DEF, ");
		else if((*ptr)->type == LABEL_REF)
			dbg("LABEL_REF, ");
		else if((*ptr)->type == VARIABLE)
			dbg("VARIABLE, ");
		else
			dbg("UNKNOWN: ERROR");
		dbg("%s\n", (*ptr)->name);
	}
}

symboll_t** check_labels(symboll_t **ptr) {
	for(; *ptr != NULL; ptr = &((*ptr)->next)) {
		if((*ptr)->type == LABEL_REF) {
			SET_STATUS(3);
			err_sym_not_defined((*ptr)->name, (*ptr)->line, (*ptr)->type);
			return NULL;
		}
	}
	return ptr;
}

symboll_t** contains(symboll_t **ptr, char *name, long line, symbolt_t type) {
	for(; *ptr != NULL; ptr = &((*ptr)->next)) {
		if(strcmp(((*ptr)->name), name) == 0) {
			if((*ptr)->type == LABEL_DEF) {
				SET_STATUS(3);
				err_sym_already_defined(*ptr, name, line, type);
				return ptr;
			} else if((*ptr)->type == LABEL_REF) {
				SET_STATUS(3);
				err_sym_already_defined(*ptr, name, line, type);
				return ptr;
			} else if((*ptr)->type == VARIABLE) {
				dbg("Found " CYAN "%s" CLR " in symlist\n", name);
				return ptr;
			} else {
				ERR("FATAL: TYPE COULD NOT BE MATCHED - SYMLIST CORRUPTED?\n");
				return NULL;
			}
		}
	}
	SET_STATUS(3);
	err_sym_not_defined(name, line, type);
	return NULL;
}

symboll_t** add(symboll_t **ptr, char *name, long line, symbolt_t type) {
	for(; *ptr != NULL; ptr = &((*ptr)->next)) {
		if(strcmp(((*ptr)->name), name) == 0) {
			if((*ptr)->type == VARIABLE) {
				SET_STATUS(3);
				err_sym_already_defined(*ptr, name, line, type);
				return ptr;
			} else if((*ptr)->type == LABEL_DEF) {
				if(type == LABEL_REF) {
					dbg("Label " CYAN "%s" CLR " found\n", (*ptr)->name);
					return ptr;
				} else {
					SET_STATUS(3);
					err_sym_already_defined(*ptr, name, line, type);
					return ptr;
				}
			} else if((*ptr)->type == LABEL_REF) {
				if(type == VARIABLE) {
					SET_STATUS(3);
					err_sym_already_defined(*ptr, name, line, type);
					return ptr;
				} else if(type == LABEL_DEF) {
					(*ptr)->type = LABEL_DEF;
					dbg("Label " CYAN "%s" CLR " referenced and found\n", (*ptr)->name);
					return ptr;
				} else {
					dbg("Label " CYAN "%s" CLR " already referenced\n", (*ptr)->name);
					return ptr;
				}
			} else {
				ERR("FATAL: TYPE COULD NOT BE MATCHED - SYMLIST CORRUPTED?\n");
				return NULL; 
			}
		}
	}

	*ptr = malloc(sizeof(symboll_t));
	(*ptr)->name = name;
	(*ptr)->type = type;
	(*ptr)->line = line;

	dbg("Added ");
	if((*ptr)->type == LABEL_DEF)
		dbg("LABEL_DEF, ");
	else if((*ptr)->type == LABEL_REF)
		dbg("LABEL_REF, ");
	else if((*ptr)->type == VARIABLE)
		dbg("VARIABLE, ");
	else
		dbg("UNKNOWN: ERROR ");
	dbg("%ld: %s\n", line, name);

	(*ptr)->next = NULL;
	return ptr;
}

void free_list(symboll_t **ptr) {
	while(*ptr != NULL) {
		dbg("Freeing %s\n", ((*ptr)->name));
		symboll_t *tmp = *ptr;
		ptr = &((*ptr)->next);
		free(tmp);
	}
}
